home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MACSHELL
/
MS1
/
SHELL_SO
/
PROC.C
< prev
next >
Wrap
Text File
|
1992-12-02
|
20KB
|
814 lines
/*
* MacShell Source File
*
* Copyright (c) 1989, 1990, 1991, 1992 Suick Bay Technologies. All rights reserved.
*
*
* RESTRICTIONS ON MacShell program and source code.
*
* Ñ╩MacShell¬ is a product of Suick Bay Technologies and is provided for
* restricted use by the owner of the CDROM "Disk to the future II".
*
* Ñ╩No permission is granted for any commercial use without the written
* consent of the Suick Bay Technologies.
*
* Ñ╩No permission is granted for any redistribution of any kind use without
* the written consent of the Suick Bay Technologies.
*
* Ñ╩Permission is granted to use this for any personal noncommercial use.
*
* Ñ╩You may not distribute source or executable code at all, nor may you
* distribute it with or within a commercial product without the written
* consent of the Suick Bay Technologies. Please send modifications to
* the author for inclusion in updates to the program. Thanks.
*
*
* MacShell¬ IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* SUICK BAY TECHNOLOGIES SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY MACSHELL
* OR ANY PART THEREOF.
*
* In no event will Suick Bay Technologies be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Suick Bay Technologies has been advised of the possibility of such damages.
*
* Suick Bay Technologies can be reached at:
*
* 8768 Cottonwood lane
* Maple Grove, MN 55369
* Voice: (612) 425-7025
* AppleLink: D5233
*
*
* No parts of this software may be reproduced or stored in a
* retrieval system or transmitted in any form, or any means,
* electronic, mechanical, photocopying, recording or otherwise,
* without the prior written permission of Suick Bay Technologies.
*
* Spread the word and not the disk.
*
* SPK 012290 : Initial
*/
#include "System.h"
#include "Parse.h"
#include "Proc.h"
#include "Path.h"
#include "Shell.h"
#include "Struct.h"
/*******************************************************************
* UTIL FUNCTIONS
*******************************************************************/
#define ValidProc(X) ((X)>=0&&(X)<MAX_PROCS&&(**MyShell).Proc[(X)].ProcActive)
GetArgv( WHandle ShellWh, int ProcID, int16 Arg, char *buf )
{
char *cp;
int16 index;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
index = (**MyShell).Proc[ ProcID ].argv[ Arg ];
cp = &((**MyShell).Proc[ ProcID ].cmdline[ index ]);
while( *buf++ = *cp++ );
}
/*******************************************************************
* STANDARD INTERFACE FUNCTIONS
*******************************************************************/
CommandString( char *string, WHandle ShellWh )
{
ProcPtr p;
ShellWindRec **MyShell;
PEHandle hPE;
int32 len;
char *sp;
if( ShellWh == NULL )
return;
MyShell = (ShellWindRec **) (**ShellWh).thing;
/*
* Send string to the input PE
*/
hPE = (**MyShell).ihPE;
PESetSelect( (**hPE).selEnd, (**hPE).selEnd, hPE );
sp = string;
while( *sp ) /* convert newlines to crs */
{
if( *sp == '\n' )
*sp = '\r';
sp++;
}
len = (int32) strlen( string );
PEInsert( string, len, hPE );
AdjustInput( ShellWh, TRUE );
}
/*******************************************************************/
WriteToStdOut( char *string, WHandle ShellWh )
{
ProcPtr p;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
p = (**MyShell).Proc[ STDOUT_PROCID ].CmdProcPtr;
if( p && ValidProc( STDOUT_PROCID ) )
(*p)( PROC_STDIN, ShellWh, STDOUT_PROCID, string );
}
/*******************************************************************/
Boolean SendToken( WHandle ShellWh, int ProcID, int token )
{
ProcPtr p;
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
if( ValidProc( ProcID ) )
{
p = (**MyShell).Proc[ ProcID ].CmdProcPtr;
#ifdef PROCDEBUG
printf( "Sending Token %d to %d\n", token, ProcID );
#endif
if( p && ValidProc( ProcID ) )
return( (*p)( token, ShellWh, ProcID, NULL ) );
}
else
return( FALSE );
}
/*******************************************************************/
Boolean SendBreakToken( WHandle ShellWh )
{
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
return( SendToken( ShellWh, STDIN_PROCID, PROC_BREAK ) );
}
/*******************************************************************/
Boolean SendOutToken( WHandle ShellWh, int ProcID, int token )
{
ProcPtr p;
int OutProcID;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
if( ValidProc( ProcID ) )
{
OutProcID = (**MyShell).Proc[ ProcID ].StdOutProcID;
p = (**MyShell).Proc[ OutProcID ].CmdProcPtr;
#ifdef PROCDEBUG
printf( "Sending STDOUT TOKEN %d from %d to %d\n",
token, ProcID, OutProcID );
#endif
if( p && ValidProc( OutProcID ) )
return( (*p)( token, ShellWh, OutProcID, NULL ) );
}
else
return( FALSE );
}
/*******************************************************************/
StdOut( WHandle ShellWh, int ProcID, char *string )
{
ProcPtr p;
int OutProcID;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
if( ValidProc( ProcID ) )
{
OutProcID = (**MyShell).Proc[ ProcID ].StdOutProcID;
p = (**MyShell).Proc[ OutProcID ].CmdProcPtr;
if( p && ValidProc( OutProcID ) )
(*p)( PROC_STDIN, ShellWh, OutProcID, string );
}
}
/*******************************************************************/
StdErr( WHandle ShellWh, int ProcID, char *string )
{
ProcPtr p;
int ErrProcID;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
if( ValidProc( ProcID ) )
{
ErrProcID = (**MyShell).Proc[ ProcID ].StdErrProcID;
p = (**MyShell).Proc[ ErrProcID ].CmdProcPtr;
if( p && ValidProc( ErrProcID ) )
(*p)( PROC_STDIN, ShellWh, ErrProcID, string );
}
}
/*******************************************************************
* SHELL INTERFACE FUNCTIONS
*
* This function write to the shell for stdout and strerr
*******************************************************************/
ShellOutProc( int ProcToken, WHandle ShellWh, int ProcID, char *string )
{
char *cp;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
if( ProcToken == PROC_STDIN && ShellWh && string )
{
cp = string;
while( *cp ) /* convert newlines to <cr> */
{
if( *cp == '\n' )
*cp = '\r';
cp++;
}
ShellAddStr( string, ShellWh );
}
else if( ProcToken == PROC_BREAK )
{
/* rewrire stdin and stdout to the shell proc */
if( ProcID != STDOUT_PROCID )
(**MyShell).Proc[ ProcID ].ProcActive = FALSE;
else
ResetStdIO( ShellWh );
}
}
/*******************************************************************/
InitProc( WHandle ShellWh, int ProcID, int inStream, int outStream, int errStream )
{
int i;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
(**MyShell).Proc[ ProcID ].ProcActive = TRUE;
/*
* Connect the streams
*/
(**MyShell).Proc[ inStream ].StdOutProcID = ProcID;
(**MyShell).Proc[ ProcID ].StdOutProcID = outStream;
(**MyShell).Proc[ ProcID ].StdErrProcID = errStream;
SendToken( ShellWh, ProcID, PROC_INIT );
}
/*******************************************************************/
/*
* Find an inactive proc slot and return it.
* If no slot is availible then return UNKNOWN
*/
int GetProcSlot( WHandle ShellWh )
{
int proc;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
for( proc = 0; proc < MAX_PROCS; proc++ )
if( (**MyShell).Proc[ proc ].ProcActive == FALSE )
return( proc );
return( UNKNOWN );
}
/********************************************************************
* Command line scanner
********************************************************************/
CLScanner( int ProcToken, WHandle ShellWh, int ProcID, char *string )
{
char *cp, **ch, buf[ 64 ],
stdInFile[ 64 ],
stdOutFile[ 64 ];
int16 currProcSlot, lastProcSlot,
pipeFromLast, pipeToNext, pipeErr,
i, ioOk, cmdc, tokenType, lastToken,
ProcDataAvail, parseErr = 0,
inProc, outProc, errProc;
ShellWindRec **MyShell;
/*
* Command execution vars
*/
ProcPtr theCommand;
int needsStdIn;
(**ShellWh).entryCnt++;
MyShell = (ShellWindRec **) (**ShellWh).thing;
lastProcSlot = CL_PROCID;
if( ProcToken == PROC_STDIN && ShellWh && string )
{
ExpandShellStr( ShellWh, string );
cp = string;
currProcSlot = GetProcSlot( ShellWh );
if( currProcSlot == UNKNOWN )
{
ShellError( se_noProcSlots );
return;
}
else /* Initialize the Proc */
{
(**MyShell).Proc[ currProcSlot ].argc = 0;
cmdc = 0;
(**MyShell).StdOutAppend = FALSE;
stdInFile[ 0 ] = '\0';
stdOutFile[ 0 ] = '\0';
lastToken = UNKNOWN;
ProcDataAvail = FALSE;
lastProcSlot = CL_PROCID;
pipeFromLast = FALSE;
pipeToNext = FALSE;
pipeErr = FALSE;
ioOk = FALSE;
}
inProc = STDIN_PROCID;
outProc = STDOUT_PROCID;
errProc = STDERR_PROCID;
while( cp )
{
cp = GetShellToken( cp, buf, &tokenType );
parseErr = 0;
#ifdef PROCDEBUG
printf( "Token : '%s' = %d\n", buf, tokenType );
#endif
switch( tokenType )
{
case tkn_andf : /* '&&' */
case tkn_orf : /* '||' */
case tkn_background : /* '&' */
break;
case tkn_pipeOutErr : /* '|&' */
pipeErr = TRUE;
case tkn_pipe : /* '|' */
pipeToNext = TRUE;
case tkn_separator : /* ';' */
case tkn_eol :
Execute:
if( tokenType == tkn_eol )
procPrintf( ShellWh, ProcID,
"%s%s", GetPromptStr( ShellWh ), string );
if( ProcDataAvail ) /* Start the process */
{
char command[ 256 ];
GetArgv( ShellWh, currProcSlot, 0, command );
if( GetCommandInfo( command, &theCommand, &needsStdIn ) )
{
forceCommand :
/* save the command */
RecordCmd( string, ShellWh );
(**MyShell).Proc[ currProcSlot ].CmdProcPtr = theCommand;
if( *stdInFile && needsStdIn ) /* init stdin */
{
ProcPtr p;
p = (**MyShell).Proc[ STDIN_PROCID ].CmdProcPtr;
if( p )
ioOk = (*p)( PROC_INIT, ShellWh, STDIN_PROCID, stdInFile );
if( ioOk == FALSE )
parseErr = se_ioRedir;
}
if( *stdOutFile ) /* init stdout */
{
ProcPtr p;
p = (**MyShell).Proc[ STDOUT_PROCID ].CmdProcPtr;
if( p )
ioOk = (*p)( PROC_INIT, ShellWh, STDOUT_PROCID, stdOutFile );
if( ioOk == FALSE )
parseErr = se_ioRedir;
}
if( pipeFromLast && (lastProcSlot != CL_PROCID))
InitProc( ShellWh, currProcSlot, lastProcSlot, outProc, errProc );
else
{
InitProc( ShellWh, currProcSlot, inProc, outProc, errProc );
if( needsStdIn && (parseErr == noErr))
{
(**MyShell).prompt = 1;
}
}
if( tokenType == tkn_separator )
{
/* command was separated on the command line
run the command until it is complete */
while( (**MyShell).Proc[ currProcSlot ].ProcActive )
ProcMgrIdle( ShellWh );
outProc = (**MyShell).Proc[ ProcID ].StdOutProcID;
errProc = (**MyShell).Proc[ ProcID ].StdErrProcID;
}
/* Set up another proc slot */
lastProcSlot = currProcSlot;
ProcDataAvail = FALSE;
pipeFromLast = pipeToNext;
currProcSlot = GetProcSlot( ShellWh );
if( currProcSlot == UNKNOWN )
{
ShellError( se_noProcSlots );
return;
}
else /* Initialize the Proc */
{
(**MyShell).Proc[ currProcSlot ].argc = 0;
cmdc = 0;
stdInFile[ 0 ] = '\0';
stdOutFile[ 0 ] = '\0';
ProcDataAvail = FALSE;
(**MyShell).StdOutAppend = FALSE;
if( tokenType == tkn_separator )
{
lastProcSlot = CL_PROCID;
pipeToNext = FALSE;
pipeFromLast = FALSE;
pipeErr = FALSE;
}
}
}
else if( BuiltInCMD( ShellWh, currProcSlot, ProcID, command ))
{
RecordCmd( command, ShellWh );
}
else /* name could be a script or an application */
{
int refNum;
char str[ 256 ];
refNum = OpenFile( ShellWh, command, 'TEXT', fsRdPerm );
if( !refNum )
{
strcpy( str, command );
strcat( str, ".script" );
refNum = OpenFile( ShellWh, str, 'TEXT', fsRdPerm );
if( refNum )
strcpy( command, str );
}
if( refNum )
{
int ni, na, nc = 0;
char *cp, *np;
FSClose( refNum );
/* save the new command and arguments */
na = (**MyShell).Proc[ currProcSlot ].argc;
/* copy command line to new script proc */
(**MyShell).Proc[ currProcSlot ].argv[ 0 ] = 0;
cp = command;
while( *cp++ )
nc++;
nc++;
/* copy argvs to new script proc */
for( ni = 1; ni < na; ni++ )
{
GetArgv( ShellWh, currProcSlot, ni, str );
(**MyShell).Proc[currProcSlot].argv[ni] = nc;
np = str;
while( *cp++ = *np++ )
nc++;
nc++;
}
for( ni = 0; ni < nc; ni++ )
(**MyShell).Proc[ currProcSlot ].cmdline[ni] = command[ni];
theCommand = (ProcPtr) DoSCRIPT;
needsStdIn = FALSE;
goto forceCommand;
}
else
{
refNum = OpenFile( ShellWh, command, 'APPL', fsRdPerm );
if( refNum )
{
pathType pt;
OsErr lerr;
FSClose( refNum );
/* application */
if( CanLaunch() == FALSE )
{
procPrintf( ShellWh, ProcID,
"sh : Applications can only be launched under MultiFinder\n" );
}
else
{
pt = SetCurrPath( command );
if( pt == pathIsFile )
{
int cv;
long cd, cp;
GetPWDInfo( &cv, &cd, &cp );
strcpy( str, GetLastScan() );
RecordCmd( str, ShellWh );
CtoPstr( str );
lerr = DoLaunch( str, cv, cd );
if( lerr )
procPrintf( ShellWh, ProcID,
"sh : can't launch %ps (%d)\n", str, lerr );
}
}
ResetShellPWD( ShellWh );
}
else
parseErr = se_unknownCmd;
}
}
}
break;
case tkn_var : /* '$' */
case tkn_identifier : /* */
case tkn_digit : /* '0-9.' */
{
char *s;
char varName[ 64 ];
/* save as argument */
if( tokenType == tkn_var )
{
if( cp )
{
cp = GetShellToken( cp, varName, &tokenType );
s = ShellGetVar( ShellWh, varName );
}
else
s = buf;
}
else
s = buf;
(**MyShell).Proc[currProcSlot].argv[
(**MyShell).Proc[currProcSlot].argc] = cmdc;
while ( (**MyShell).Proc[ currProcSlot ].cmdline[ cmdc++ ] = *s++ );
(**MyShell).Proc[ currProcSlot ].argc++;
ProcDataAvail = TRUE;
}
break;
case tkn_inputRedirect: /* '<' */
if( cp )
{
cp = GetShellToken( cp, stdInFile, &tokenType );
if( tokenType != tkn_identifier )
parseErr = se_expectFile;
}
else
parseErr = se_expectFile;
break;
case tkn_outputAppend: /* '>>' */
(**MyShell).StdOutAppend = TRUE;
case tkn_outputRedirect: /* '>' */
if( cp )
{
cp = GetShellToken( cp, stdOutFile, &tokenType );
if( tokenType != tkn_identifier )
parseErr = se_expectFile;
}
else
parseErr = se_expectFile;
break;
case tkn_comment : /* '#' */
while( cp )
{
cp = GetShellToken( cp, stdOutFile, &tokenType );
if( tokenType == tkn_eol )
break;
}
goto Execute;
break;
default :
break;
}
if( parseErr )
break;
}
lastToken = tokenType;
}
/*
* Start execution of any commands
*/
if( parseErr )
{
procPrintf( ShellWh, ProcID, "%s", string );
ShellError( parseErr );
}
if( lastProcSlot != CL_PROCID )
ProcMgrIdle( ShellWh );
(**ShellWh).entryCnt--;
}
/*******************************************************************/
/*
* Receive raw input from the command line
* Break into lines
*/
ShellTextInput( Handle theText, long len, WHandle ShellWh )
{
char buf[ 256 ], *cp;
long i = 0, total = 0;
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
cp = *theText;
cp += (**MyShell).promptBase;
len -= (**MyShell).promptBase;
while( *cp && total < len )
{
/* Copy a line */
i = 0;
while( total < len )
{
if( !(*cp) || (*cp == '\n') || (*cp == '\r') || (i > 250 ))
break;
buf[i++] = *cp++;
total++;
}
if( *cp == '\n' || *cp == '\r' )
buf[ i++ ] = '\n';
buf[ i++ ] = '\0'; /* end of this string */
CommandString( buf, ShellWh );
if( total >= len || *cp == '\0' )
break;
else if( (*cp == '\n') || (*cp == '\r') )
{
cp++;
total++;
}
}
}
/*******************************************************************
* Init the process manager
*
* The stdIn should be sent to the command line scanner
* The stdOut and strErr is sent to the shell
*
*******************************************************************/
ResetStdIO( WHandle ShellWh )
{
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
if( (**MyShell).prompt != 0 )
{
(**MyShell).prompt = 0;
CleanShellInput( ShellWh );
}
#ifdef PROCDEBUG
printf( "ResetStdIO\n" );
#endif
/*
* Setup standard output
*/
(**MyShell).Proc[ STDOUT_PROCID ].CmdProcPtr = (ProcPtr) StdOutProc;
(**MyShell).Proc[ STDOUT_PROCID ].ProcActive = TRUE;
/*
* Setup standard error
*/
(**MyShell).Proc[ STDERR_PROCID ].CmdProcPtr = (ProcPtr) StdErrProc;
(**MyShell).Proc[ STDERR_PROCID ].ProcActive = TRUE;
/*
* Setup standard input
*/
(**MyShell).Proc[ STDIN_PROCID ].CmdProcPtr = (ProcPtr) StdInProc;
(**MyShell).Proc[ STDIN_PROCID ].ProcActive = TRUE;
(**MyShell).Proc[ STDIN_PROCID ].StdOutProcID = CL_PROCID;
/*
* Setup shell scanner
*/
(**MyShell).Proc[ CL_PROCID ].CmdProcPtr = (ProcPtr) CLScanner;
(**MyShell).Proc[ CL_PROCID ].ProcActive = TRUE;
}
/*******************************************************************/
InitProcMgr( WHandle ShellWh )
{
int p;
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
(**MyShell).ShellWh = ShellWh;
for( p = 0; p < MAX_PROCS; p++ ) /* Clean records */
{
(**MyShell).Proc[ p ].ProcActive = FALSE;
(**MyShell).Proc[ p ].ProcID = p;
(**MyShell).Proc[ p ].fileRefNum = 0;
(**MyShell).Proc[ p ].CmdProcPtr = ShellOutProc;
(**MyShell).Proc[ p ].argc = UNKNOWN;
(**MyShell).Proc[ p ].StdOutProcID = STDOUT_PROCID;
(**MyShell).Proc[ p ].StdErrProcID = STDERR_PROCID;
(**MyShell).Proc[ p ].locStorage = NULL;
(**MyShell).Proc[ p ].flags = 0;
}
(**MyShell).numProcs = 4;
ResetStdIO( ShellWh );
}
/*******************************************************************
* This function is called by the Idle method of a shell
* It monitors all procs and send messages between them if needed.
*******************************************************************/
ProcMgrIdle( WHandle ShellWh )
{
int i, start = 0;
ProcPtr p;
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
for( i = start; i < MAX_PROCS; i++ )
if( (**MyShell).Proc[ i ].ProcActive )
{
p = (**MyShell).Proc[ i ].CmdProcPtr;
if( p )
(*p)( PROC_STDIN, ShellWh, i, NULL );
}
}